package com.alex.wechat.mp.gateway;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alex.wechat.mp.config.WxConsts;
import com.alex.wechat.mp.config.WxContext;
import com.alex.wechat.mp.util.WxCryptUtilEx;

import me.chanjar.weixin.message.bean.WxXmlMessage;
import me.chanjar.weixin.message.rule.WxMessageRouter;
import me.chanjar.weixin.mp.api.WxMpConfigStorage;

/**
 * 负责与微信服务器通信。
 * 
 * @author Debenson
 * @since 0.1
 */
@Controller
@RequestMapping("/wxCoreController")
public class WxCoreController {
  private final Logger logger = LoggerFactory.getLogger(WxCoreController.class);

  @Autowired
  private WxMpConfigStorage configStorage;
  @Autowired
  private WxMessageRouter wxMsgRouter;

  /**
   * 微信公众号webservice主服务接口，提供与微信服务器的信息交互
   *
   * @param request
   * @param response
   * @throws Exception
   */
  @RequestMapping(params = "wechat")
  public void wechat(HttpServletRequest request, HttpServletResponse response) throws Exception {
    response.setContentType("text/html;charset=utf-8");
    response.setStatus(HttpServletResponse.SC_OK);

    if (!WxCryptUtilEx.checkSignature(configStorage.getToken(), request)) {
      // 消息签名不正确，说明不是公众平台发过来的消息
      response.getWriter().println("非法请求");
      return;
    }

    final String echoStr = request.getParameter(WxConsts.PARAM_ECHO_STR);
    if (StringUtils.isNotBlank(echoStr)) {
      // 说明是一个仅仅用来验证的请求，回显echostr
      String echoStrOut = String.copyValueOf(echoStr.toCharArray());
      response.getWriter().println(echoStrOut);
      return;
    }

    String encryptType = request.getParameter(WxConsts.PARAM_ENCRYPT_TYPE);
    if (StringUtils.isBlank(encryptType)) {
      encryptType = WxConsts.ENCRYPT_TYPE_RAW;
    }
    if (WxConsts.ENCRYPT_TYPE_RAW.equalsIgnoreCase(encryptType)) {
      // 使用明码传输
      processRawEncrypt(request, response);

    } else if (WxConsts.ENCRYPT_TYPE_AES.equalsIgnoreCase(encryptType)) {
      // 是aes加密的消息
      processAesEncrypt(request, response);

    } else {
      response.getWriter().println("不可识别的加密类型");
    }
  }

  /**
   * 处理明文请求。
   * 
   * @param request
   * @param response
   * @throws Exception
   */
  private void processRawEncrypt(HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    // 明文传输的消息
    response.setContentType("application/xml; charset=UTF-8");
    WxXmlMessage inMessage = WxXmlMessage.fromXml(request.getInputStream());

    initWxContext(inMessage);
    final String outMessage = this.wxMsgRouter.routeMp(inMessage);
    if (outMessage != null) {
      if (logger.isInfoEnabled()) {
        logger.info("回复内容为: {}", outMessage);
      }
      response.getWriter().write(outMessage);
    }
  }

  /**
   * 处理加密请求。
   * 
   * @param request
   * @param response
   * @throws Exception
   */
  private void processAesEncrypt(HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    final String msgSignature = request.getParameter(WxConsts.PARAM_MSG_SIGNATURE);
    final String nonce = request.getParameter(WxConsts.PARAM_NONCE);
    final String timestamp = request.getParameter(WxConsts.PARAM_TIMESTAMP);
    response.setContentType("application/xml; charset=UTF-8");

    WxXmlMessage inMessage = WxCryptUtilEx.fromEncryptedXml(request.getInputStream(), configStorage,
        timestamp, nonce, msgSignature);
    if (logger.isInfoEnabled()) {
      logger.info("公众号消息解密后内容为：\n{} ", inMessage.toString());
    }

    initWxContext(inMessage);
    final String outMessage = this.wxMsgRouter.routeMp(inMessage);
    if (outMessage != null) {
      if (logger.isInfoEnabled()) {
        logger.info("回复公众号内容为(加密前): {}", outMessage);
      }
      response.getWriter().write(WxCryptUtilEx.toEncryptedXml(outMessage, configStorage));
    } else {
      if (logger.isInfoEnabled()) {
        logger.info("没有回复内容");
      }
    }
  }

  /**
   * 初始化微信上下文环境。
   * 
   * @param inMessage
   */
  private void initWxContext(WxXmlMessage inMessage) {
    // 设置当前公众号
    WxContext.setOriginalId(inMessage.getToUser());

    // 设置当前粉丝
    WxContext.setOpenId(inMessage.getFromUser());
  }

  // /**
  // * 检验签名。
  // *
  // * @return
  // */
  // private boolean checkSignature(HttpServletRequest request) {
  // // 否则只能一一校验签名，这里要求每一个账户的token是不一样的。
  // final String signature = request.getParameter(WxConsts.PARAM_SIGNATURE);
  // final String nonce = request.getParameter(WxConsts.PARAM_NONCE);
  // final String timestamp = request.getParameter(WxConsts.PARAM_TIMESTAMP);
  // return SignUtil.checkSignature(configStorage.getToken(), signature,
  // timestamp, nonce);
  // }

  // /**
  // * 通过openid获得基本用户信息 详情请见:
  // * http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html
  // *
  // * @param response
  // * @param openid
  // * openid
  // * @param lang
  // * zh_CN, zh_TW, en
  // */
  // @RequestMapping(value = "getUserInfo")
  // public WxMpUser getUserInfo(HttpServletResponse response,
  // @RequestParam(value = "openid") String openid, @RequestParam(value =
  // "lang") String lang) {
  // ReturnModel returnModel = new ReturnModel();
  // WxMpUser wxMpUser = null;
  // try {
  // wxMpUser = this.wxMpService.getUserService().userInfo(openid, lang);
  // returnModel.setResult(true);
  // returnModel.setDatum(wxMpUser);
  // renderString(response, returnModel);
  // } catch (WxErrorException e) {
  // returnModel.setResult(false);
  // returnModel.setReason(e.getError().toString());
  // renderString(response, returnModel);
  // logger.error(e.getError().toString());
  // }
  // return wxMpUser;
  // }
  //
  // /**
  // * 通过code获得基本用户信息 详情请见:
  // * http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html
  // *
  // * @param response
  // * @param code
  // * code
  // * @param lang
  // * zh_CN, zh_TW, en
  // */
  // @RequestMapping(value = "getOAuth2UserInfo")
  // public void getOAuth2UserInfo(HttpServletResponse response,
  // @RequestParam(value = "code") String code, @RequestParam(value = "lang")
  // String lang) {
  // ReturnModel returnModel = new ReturnModel();
  // WxMpOAuth2AccessToken accessToken;
  // WxMpUser wxMpUser;
  // try {
  // accessToken = this.wxMpService.oauth2getAccessToken(code);
  // wxMpUser =
  // this.wxMpService.getUserService().userInfo(accessToken.getOpenId(), lang);
  // returnModel.setResult(true);
  // returnModel.setDatum(wxMpUser);
  // renderString(response, returnModel);
  // } catch (WxErrorException e) {
  // returnModel.setResult(false);
  // returnModel.setReason(e.getError().toString());
  // renderString(response, returnModel);
  // logger.error(e.getError().toString());
  // }
  // }
  //
  // /**
  // * 用code换取oauth2的openid 详情请见:
  // * http://mp.weixin.qq.com/wiki/1/8a5ce6257f1d3b2afb20f83e72b72ce9.html
  // *
  // * @param response
  // * @param code
  // * code
  // */
  // @RequestMapping(value = "getOpenid")
  // public void getOpenid(HttpServletResponse response, @RequestParam(value =
  // "code") String code) {
  // ReturnModel returnModel = new ReturnModel();
  // WxMpOAuth2AccessToken accessToken;
  // try {
  // accessToken = this.wxMpService.oauth2getAccessToken(code);
  // returnModel.setResult(true);
  // returnModel.setDatum(accessToken.getOpenId());
  // renderString(response, returnModel);
  // } catch (WxErrorException e) {
  // returnModel.setResult(false);
  // returnModel.setReason(e.getError().toString());
  // renderString(response, returnModel);
  // logger.error(e.getError().toString());
  // }
  // }

}
